//+------------------------------------------------------------------+
//|                                                  DualMA_EA.mq5   |
//|                        Copyright 2023, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.01"  // 版本号更新
#include <Trade\Trade.mqh>

input int      FastMAPeriod = 1;          // 快线周期
input int      SlowMAPeriod = 10;         // 慢线周期
input double   Lots = 0.01;                 // 交易手数
input int      StopLossPoints = 500;       // 止损点数
input int      TakeProfitPoints = 250;     // 止盈点数
input ulong    MagicNumber = 12345;       // EA魔术号
input int      kCount = 16; // 前20K线数量
input int      limtOrder=10; // 限制数量
input double   MinProfit = -2.8; // 最小盈利值小于平仓
bool triggered = false; // 防止重复触发标志



int ssfastMA, fastMA, slowMA;
datetime lastBarTime;
CTrade trade;


//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   trade.SetExpertMagicNumber(MagicNumber);
   fastMA = iMA(_Symbol, PERIOD_CURRENT, FastMAPeriod, 0, MODE_SMA, PRICE_CLOSE);
   slowMA = iMA(_Symbol, PERIOD_CURRENT, SlowMAPeriod, 0, MODE_SMA, PRICE_CLOSE);
   trade.SetExpertMagicNumber(MagicNumber);
   return(INIT_SUCCEEDED);
  }

//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   EventKillTimer(); // 删除定时器
  }

//+------------------------------------------------------------------+
//| Timer function                                                   |
//+------------------------------------------------------------------+
void OnTimer()
  {

  }

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
// 检查时间条件（K线结束前5秒内）
//if(!triggered) return;
// 检查新K线
   datetime currentBarTime = iTime(_Symbol, _Period, 0);
   if(lastBarTime == currentBarTime)
      return;
   lastBarTime = currentBarTime;

// 获取均线值
   double  fastMAValues[3], slowMAValues[3];
//CopyBuffer(ssfastMA, 0, 1, 2, ssfastMAValues);
   CopyBuffer(fastMA, 0, 1, 2, fastMAValues);
   CopyBuffer(slowMA, 0, 1, 2, slowMAValues);
   ArraySetAsSeries(fastMAValues, true);
   ArraySetAsSeries(slowMAValues, true);


// 检查交叉信号
   bool goldenCross = (fastMAValues[1] > slowMAValues[1]) && (fastMAValues[0] <= slowMAValues[0]);
   bool deathCross = (fastMAValues[1] < slowMAValues[1]) && (fastMAValues[0] >= slowMAValues[0]);



// 处理交易信号
   if(goldenCross)
     {
      // CloseAllPositions();  // 平掉所有仓位
      // OpenBuyPosition();
     }
   else
      if(deathCross && checkOrderBeforeTenK())
        {
         CloseAllPositions();  // 平掉所有仓位
         OpenSellPosition();
        }

// 检查移动止损条件
// CheckTrailingStop();
  }

//+------------------------------------------------------------------+
//| 开多单（增加持仓检查）                                           |
//+------------------------------------------------------------------+
void OpenBuyPosition()
  {
// 检查是否已有持仓
   if(PositionSelect(_Symbol))
      return;

   double price = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
   double sl = price - StopLossPoints * _Point;
   double tp = price + TakeProfitPoints * _Point;

   trade.PositionOpen(_Symbol, ORDER_TYPE_BUY, Lots, price, sl, tp, "Golden Cross Entry");
  }

//+------------------------------------------------------------------+
//| 开空单（增加持仓检查）                                           |
//+------------------------------------------------------------------+
void OpenSellPosition()
  {
// 检查是否已有持仓
   if(PositionSelect(_Symbol))
      return;

   double price = SymbolInfoDouble(_Symbol, SYMBOL_BID);
   double sl = price + StopLossPoints * _Point;
   double tp = price - TakeProfitPoints * _Point;

   trade.PositionOpen(_Symbol, ORDER_TYPE_SELL, Lots, price, sl, tp, "Death Cross Entry");
  }


//+------------------------------------------------------------------+
//| 获取当前订单前N判断当前趋势                                 |
//+------------------------------------------------------------------+
bool checkOrderBeforeTenK()
  {
   double closes[];
   ArraySetAsSeries(closes, true);

// 获取最近10根K线收盘价
   if(CopyClose(_Symbol, _Period, 0, kCount, closes) < kCount)
     {
      Print("Error getting price data!");
      return false;
     }

// 计算线性回归斜率
   double sum_x = 0, sum_y = 0, sum_xy = 0, sum_x2 = 0;
   for(int i=0; i<kCount; i++)
     {
      Print("k1",1);
      sum_x += i;
      sum_y += closes[i];
      sum_xy += i * closes[i];
      sum_x2 += i * i;
     }
   double slope = (kCount * sum_xy - sum_x * sum_y) / (kCount * sum_x2 - sum_x * sum_x);
   Print("k1===",slope,slope < 0);
// 判断下降趋势
   if(slope < 0.3)
     {
      return true;
     }
   else
     {
      return false;
     }
  }


//+------------------------------------------------------------------+
//| 平所有仓位                                                       |
//+------------------------------------------------------------------+
void CloseAllPositions()
  {
   for(int i = PositionsTotal()-1; i >= 0; i--)
     {
      ulong ticket = PositionGetTicket(i);
      if(PositionGetString(POSITION_SYMBOL) == _Symbol &&
         PositionGetInteger(POSITION_MAGIC) == MagicNumber)
        {
         double openPrice = PositionGetDouble(POSITION_PRICE_OPEN);
         double currentSL = PositionGetDouble(POSITION_SL);
         double currentTP = PositionGetDouble(POSITION_TP);
         double currentPrice = SymbolInfoDouble(_Symbol, SYMBOL_BID);
         double requiredPrice = openPrice + openPrice;
         double profit = PositionGetDouble(POSITION_PROFIT);
         if(currentPrice/requiredPrice >= 1.25)
           {
            trade.PositionClose(ticket);
           }
         else
           {
            if(checkOrderBeforeTenK() && currentPrice/openPrice<0.8)
              {
               trade.PositionClose(ticket);
              }
            else
               if(profit < MinProfit)
                 {
                  trade.PositionClose(ticket);
                 }
               else
                 {
                  if(PositionsTotal()<limtOrder)
                    {
                     double price = SymbolInfoDouble(_Symbol, SYMBOL_BID);
                     double sl = price + StopLossPoints * _Point;
                     double tp = price - TakeProfitPoints * _Point;
                     trade.PositionOpen(_Symbol, ORDER_TYPE_SELL, Lots, price, sl, tp, "Death Cross Entry");
                    }
                 }
           }
        }
     }
  }

//+------------------------------------------------------------------+
//| 检查移动止损条件                                                 |
//+------------------------------------------------------------------+
void CheckTrailingStop()
  {
   if(!PositionSelect(_Symbol))
      return;

   double openPrice = PositionGetDouble(POSITION_PRICE_OPEN);
   double currentSL = PositionGetDouble(POSITION_SL);
   double currentTP = PositionGetDouble(POSITION_TP);
   ENUM_POSITION_TYPE type = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);

   if(type == POSITION_TYPE_BUY)
     {
      double currentPrice = SymbolInfoDouble(_Symbol, SYMBOL_BID);
      double requiredPrice = openPrice + (TakeProfitPoints * _Point) * 0.5;

      if(currentPrice >= requiredPrice && currentSL < openPrice)
        {
         trade.PositionModify(PositionGetInteger(POSITION_TICKET), openPrice, currentTP);
        }
     }
   else
      if(type == POSITION_TYPE_SELL)
        {
         double currentPrice = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
         double requiredPrice = openPrice - (TakeProfitPoints * _Point) * 0.5;

         if(currentPrice <= requiredPrice && currentSL > openPrice)
           {
            trade.PositionModify(PositionGetInteger(POSITION_TICKET), openPrice, currentTP);
           }
        }
  }
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
